home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / rsynth / src / text.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  8.2 KB  |  364 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "proto.h"
  6. #include "darray.h"
  7. #include "phtoelm.h"
  8. #include "text.h"
  9. #include "say.h"
  10.  
  11. #define FALSE (0)
  12. #define TRUE (!0)
  13.  
  14. /*
  15. **      English to Phoneme translation.
  16. **
  17. **      Rules are made up of four parts:
  18. **
  19. **              The left context.
  20. **              The text to match.
  21. **              The right context.
  22. **              The phonemes to substitute for the matched text.
  23. **
  24. **      Procedure:
  25. **
  26. **              Seperate each block of letters (apostrophes included)
  27. **              and add a space on each side.  For each unmatched
  28. **              letter in the word, look through the rules where the
  29. **              text to match starts with the letter in the word.  If
  30. **              the text to match is found and the right and left
  31. **              context patterns also match, output the phonemes for
  32. **              that rule and skip to the next unmatched letter.
  33. **
  34. **
  35. **      Special Context Symbols:
  36. **
  37. **              #       One or more vowels
  38. **              :       Zero or more consonants
  39. **              ^       One consonant.
  40. **              .       One of B, D, V, G, J, L, M, N, R, W or Z (voiced
  41. **                      consonants)
  42. **              %       One of ER, E, ES, ED, ING, ELY (a suffix)
  43. **                      (Right context only)
  44. **              +       One of E, I or Y (a "front" vowel)
  45. */
  46.  
  47.  
  48. typedef char *Rule[4];
  49.                                 /* A rule is four character pointers */
  50. extern Rule *Rules[];
  51.                                 /* An array of pointers to rules */
  52.  
  53.  
  54. int
  55. isvowel(chr)
  56. int chr;
  57. {
  58.  return (chr == 'A' || chr == 'E' || chr == 'I' ||
  59.          chr == 'O' || chr == 'U');
  60. }
  61.  
  62. int
  63. isconsonant(chr)
  64. int chr;
  65. {
  66.  return (isupper(chr) && !isvowel(chr));
  67. }
  68.  
  69. static int leftmatch PROTO((char *pattern, char *context));
  70.  
  71. static int
  72. leftmatch(pattern, context)
  73. char *pattern;    /* first char of pattern to match in text */
  74. char *context;    /* last char of text to be matched */
  75. {
  76.  char *pat;
  77.  char *text;
  78.  int count;
  79.  if (*pattern == '\0')
  80.                                 /* null string matches any context */
  81.   {
  82.    return TRUE;
  83.   }
  84.  
  85.  /* point to last character in pattern string */
  86.  count = strlen(pattern);
  87.  pat = pattern + (count - 1);
  88.  text = context;
  89.  for (; count > 0; pat--, count--)
  90.   {
  91.    /* First check for simple text or space */
  92.    if (isalpha(*pat) || *pat == '\'' || *pat == ' ')
  93.     if (*pat != *text)
  94.      return FALSE;
  95.     else
  96.      {
  97.       text--;
  98.       continue;
  99.      }
  100.    switch (*pat)
  101.     {
  102.      case '#':                 /* One or more vowels */
  103.       if (!isvowel(*text))
  104.        return FALSE;
  105.       text--;
  106.       while (isvowel(*text))
  107.        text--;
  108.       break;
  109.      case ':':                 /* Zero or more consonants */
  110.       while (isconsonant(*text))
  111.        text--;
  112.       break;
  113.      case '^':                 /* One consonant */
  114.       if (!isconsonant(*text))
  115.        return FALSE;
  116.       text--;
  117.       break;
  118.      case '.':                 /* B, D, V, G, J, L, M, N, R, W, Z */
  119.       if (*text != 'B' && *text != 'D' && *text != 'V'
  120.           && *text != 'G' && *text != 'J' && *text != 'L'
  121.           && *text != 'M' && *text != 'N' && *text != 'R'
  122.           && *text != 'W' && *text != 'Z')
  123.        return FALSE;
  124.       text--;
  125.       break;
  126.      case '+':                 /* E, I or Y (front vowel) */
  127.       if (*text != 'E' && *text != 'I' && *text != 'Y')
  128.        return FALSE;
  129.       text--;
  130.       break;
  131.      case '%':
  132.      default:
  133.       fprintf(stderr, "Bad char in left rule: '%c'\n", *pat);
  134.       return FALSE;
  135.     }
  136.   }
  137.  return TRUE;
  138. }
  139.  
  140. static int rightmatch PROTO((char *pattern, char *context));
  141.  
  142. static int
  143. rightmatch(pattern, context)
  144. char *pattern;    /* first char of pattern to match in text */
  145. char *context;    /* last char of text to be matched */
  146. {
  147.  char *pat;
  148.  char *text;
  149.  if (*pattern == '\0')
  150.   /* null string matches any context */
  151.   return TRUE;
  152.  pat = pattern;
  153.  text = context;
  154.  for (pat = pattern; *pat != '\0'; pat++)
  155.   {
  156.    /* First check for simple text or space */
  157.    if (isalpha(*pat) || *pat == '\'' || *pat == ' ')
  158.     if (*pat != *text)
  159.      return FALSE;
  160.     else
  161.      {
  162.       text++;
  163.       continue;
  164.      }
  165.    switch (*pat)
  166.     {
  167.      case '#':                 /* One or more vowels */
  168.       if (!isvowel(*text))
  169.        return FALSE;
  170.       text++;
  171.       while (isvowel(*text))
  172.        text++;
  173.       break;
  174.      case ':':                 /* Zero or more consonants */
  175.       while (isconsonant(*text))
  176.        text++;
  177.       break;
  178.      case '^':                 /* One consonant */
  179.       if (!isconsonant(*text))
  180.        return FALSE;
  181.       text++;
  182.       break;
  183.      case '.':                 /* B, D, V, G, J, L, M, N, R, W, Z */
  184.       if (*text != 'B' && *text != 'D' && *text != 'V'
  185.           && *text != 'G' && *text != 'J' && *text != 'L'
  186.           && *text != 'M' && *text != 'N' && *text != 'R'
  187.           && *text != 'W' && *text != 'Z')
  188.        return FALSE;
  189.       text++;
  190.       break;
  191.      case '+':                 /* E, I or Y (front vowel) */
  192.       if (*text != 'E' && *text != 'I' && *text != 'Y')
  193.        return FALSE;
  194.       text++;
  195.       break;
  196.      case '%':                 /* ER, E, ES, ED, ING, ELY (a suffix) */
  197.       if (*text == 'E')
  198.        {
  199.         text++;
  200.         if (*text == 'L')
  201.          {
  202.           text++;
  203.           if (*text == 'Y')
  204.            {
  205.             text++;
  206.             break;
  207.            }
  208.           else
  209.            {
  210.             text--;      /* Don't gobble L */
  211.             break;
  212.            }
  213.          }
  214.         else if (*text == 'R' || *text == 'S' || *text == 'D')
  215.          text++;
  216.         break;
  217.        }
  218.       else if (*text == 'I')
  219.        {
  220.         text++;
  221.         if (*text == 'N')
  222.          {
  223.           text++;
  224.           if (*text == 'G')
  225.            {
  226.             text++;
  227.             break;
  228.            }
  229.          }
  230.         return FALSE;
  231.        }
  232.       else
  233.        return FALSE;
  234.      default:
  235.       fprintf(stderr, "Bad char in right rule:'%c'\n", *pat);
  236.       return FALSE;
  237.     }
  238.   }
  239.  return TRUE;
  240. }
  241.  
  242. static int find_rule PROTO((void *arg, out_p out, char *word, int index, Rule(*rules)));
  243.  
  244. static int
  245. find_rule(arg, out, word, index, rules)
  246. void *arg;
  247. out_p out;
  248. char *word;
  249. int index;
  250. Rule(*rules);
  251. {
  252.  Rule *rule;
  253.  char *left, *match, *right, *output;
  254.  int remainder;
  255.  for (;;)               /* Search for the rule */
  256.   {
  257.    rule = rules++;
  258.    match = (*rule)[1];
  259.    if (match == 0)
  260.     /* bad symbol! */
  261.     {
  262.      fprintf(stderr,
  263.           "Error: Can't find rule for: '%c' in \"%s\"\n", word[index], word);
  264.  
  265.      return index + 1;
  266.      /* Skip it! */
  267.  
  268.     }
  269.    for (remainder = index; *match != '\0'; match++, remainder++)
  270.     {
  271.      if (*match != word[remainder])
  272.       break;
  273.     }
  274.    if (*match != '\0')
  275.     /* found missmatch */
  276.     continue;
  277.  
  278.    /*
  279.       printf("\nWord: \"%s\", Index:%4d, Trying: \"%s/%s/%s\" = \"%s\"\n",
  280.       word, index, (*rule)[0], (*rule)[1], (*rule)[2], (*rule)[3]);
  281.     */
  282.    left = (*rule)[0];
  283.  
  284.    right = (*rule)[2];
  285.  
  286.  
  287.    if (!leftmatch(left, &word[index - 1]))
  288.  
  289.     continue;
  290.  
  291.    /* printf("leftmatch(\"%s\",\"...%c\") succeded!\n", left, word[index-1]); */
  292.    if (!rightmatch(right, &word[remainder]))
  293.  
  294.     continue;
  295.  
  296.    /* printf("rightmatch(\"%s\",\"%s\") succeded!\n", right, &word[remainder]); */
  297.    output = (*rule)[3];
  298.  
  299.    /* printf("Success: "); */
  300.    (*out) (arg, output);
  301.    return remainder;
  302.   }
  303. }
  304.  
  305. static void guess_word PROTO((void *arg, out_p out, char *word));
  306.  
  307. static void
  308. guess_word(arg, out, word)
  309. void *arg;
  310. out_p out;
  311. char *word;
  312. {
  313.  int index;           /* Current position in word */
  314.  int type;             /* First letter of match part */
  315.  index = 1;           /* Skip the initial blank */
  316.  do
  317.   {
  318.    if (isupper(word[index]))
  319.     type = word[index] - 'A' + 1;
  320.    else
  321.     type = 0;
  322.    index = find_rule(arg, out, word, index, Rules[type]);
  323.   }
  324.  while (word[index] != '\0');
  325. }
  326.  
  327.  
  328. static void phone_cat PROTO((void *arg, char *s));
  329.  
  330. static void
  331. phone_cat(arg, s)
  332. void *arg;
  333. char *s;
  334. {
  335.  darray_ptr p = arg;
  336.  char ch;
  337.  while ((ch = *s++))
  338.   phone_append(p, ch);
  339. }
  340.  
  341. int
  342. NRL(s, n, phone)
  343. char *s;
  344. unsigned n;
  345. darray_ptr phone;
  346. {
  347.  int old = phone->items;
  348.  char *word = malloc(n + 3);
  349.  char *d = word;
  350.  *d++ = ' ';
  351.  while (n-- > 0)
  352.   {
  353.    char ch = *s++;
  354.    if (islower(ch))
  355.     ch = toupper(ch);
  356.    *d++ = ch;
  357.   }
  358.  *d++ = ' ';
  359.  *d = '\0';
  360.  guess_word(phone, phone_cat, word);
  361.  free(word);
  362.  return phone->items - old;
  363. }
  364.